Em POO, falando em termos computacionais, o conceito de heranças tem dois aspectos fundamentais:
1. Reaproveitar o código de uma classe (classe-pai/super-classe) em diversas outras classes (classes-filhas).
2. Adicionar o tipo da classe-pai aos tipos das classes-filhas.
Todos os atributos e métodos da classe-pai (super-classe) estarão presentes nas classes filhas automaticamente. No entanto, valem os encapsulamentos, o que for private não terá visibilidade mesmo na classe filha.
A palavra extends nas classes-filhas indica herança.
Fazemos herança seguindo a forma: <encapsulamento> class <nome_da_classe> extends <nome_da_superclasse>{ }
Mas cuidado: No JAVA só é permitido herdar UMA super-classe
A dica é: Filhos só tem 1 pai. Pai tem n filhos.
Usar a super-classe para representar qualquer tipo filho é um conceito-chave de POO chamado POLIMORFISMO.
Dissemos que no JAVA em qualquer classe só é permitido fazer herança de 1 classe.
No entanto, existem situações em que gostaríamos de fazer herança de mais de uma super-classe, nesses casos temos que encadear as heranças.
Ou seja, podemos fazer a super-classe herdar outra super-classe em vez da classe filha fazer herança múltipla.
Em outras palavras, podemos fazer apenas 1 herança direta em cada classe, mas podemos herdar indiretamente qualquer número de classes.
O motivo para esse tipo de arquitetura é que no JAVA, assim como em outras liguagens, todas as classes tem uma super-classe em comum.
No JAVA todas as classes herdam a classe Object, portanto, qualquer classe tem o tipo Object.
Essa herança é implícita, mesmo sem o comando extends todas as classes herdam Object.
Mas porque a herança de Object faz com que mais de uma herança direta seja ilegal, mas heranças indiretas sejam permitidas? Se isso acontecer, a Classe acabará herdando Object duas vezes.
Isso quer dizer que se o compilador não restringisse, acabaríamos com duas cópias de todos os atributos e métodos de Object na Classe. E classes não podem ter atributos com mesmo nome ou métodos com a mesma assinatura, portanto, teríamos um monte de erros.
Usamos a técnica de sobrescrita de métodos para fazer em uma classe-filha uma implementação diferente para um método da super-classe.
Colocamos a diretiva @Override, indicando para o JAVA que não estamos criando um método novo, estamos sobrescrevendo o que já existe.
Em suma, para sobrescrever a implementação de um método da super-classe em uma classe-filha crie um método na classe-filha com a mesma assinatura do método da classe-pai e na linha anterior utilize o comando @Override.
É possível utilizar a implementação original usando a diretiva super.
Para entender como isso é possível precisamos entender como o JAVA gerencia a herança.
Para todo objeto criado a partir de classes derivadas (filhas) o JAVA cria um objeto da classe-pai.
O JAVA instancia a superclasse automaticamente e vincula as duas.
Existe na memória um objeto da classe-pai vinculado ao ciclo de vida de cada objeto da classe-filha.
Esse é o motivo pelo qual temos acesso aos atributos e métodos da superclasse, mesmo aqueles que sobrescrevemos na classe-filha.
Por conta disso, construtores da superclasse e das classes-filhas devem ter o mesmo conjunto de parâmetros, ou o código não compilará!
Para fazer isso usamos super,como método: super(). Isso é equivalente o this() que invocava o construtor da própria classe, mas para a classe-pai.
Em resumo, para invocar um construtor da superclasse use super().
Você também pode usar o super() para escolher qual construtor da superclasse rodar se houver mais de um.
Lembre-se, super() só pode ser invocado na primeira linha do construtor da classe-filha.